//-----------------------------------------------------------------------
// <copyright file="AddUser.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary>Adds an Active Directory User to either a domain group or a local group.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.ActiveDirectory.Group
{
    using System;
    using Microsoft.Build.Framework;
    using AD = Microsoft.Sdc.Tasks.Configuration.ActiveDirectory;

    /// <summary>
    /// Adds an Active Directory User to either a domain group or a local group.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[<ActiveDirectory.Group.AddUser 
    ///     UserName="userName" 
    ///     GroupName="groupName" 
    ///     UserDomain="userDomain" 
    ///     GroupDomain="groupDomain"
    ///     GroupMachine="groupMachine"
    ///     EnsureUserIsInGroup="ensureUserIsInGroup" />]]></code>
    /// <para>where:</para>
    /// <para><i>userName (Required)</i></para>
    /// <para>The name of the user to add to the group.</para>
    /// <para><i>groupName (Required)</i></para>
    /// <para>The groupname to add the user to.</para>
    /// <para><i>userDomain</i></para>
    /// <para>The domain the user belongs to. If not specified it defaults to the local machine.</para>
    /// <para><i>groupDomain</i></para>
    /// <para>The domain the group belongs to. Specify either this or GroupMachine. If neither are specified then a group on the local machine is assumed.</para>
    /// <para><i>groupMachine</i></para>
    /// <para>The machine the group belongs to. Specify either this or GroupDomain. If neither are specified then a group on the local machine is assumed.</para>
    /// <para><i>ensureUserIsInGroup</i></para>
    /// <para>If "true" and the User is already in the group then no error is thrown. If false, an error will 
    /// be thrown if the specified user is already a member of the specified group. Defaults to false. </para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <ActiveDirectory.Group.AddUser
    ///             UserName="user1"
    ///             GroupName="Domain Administrators"
    ///             UserDomain="mydomain"
    ///             GroupDomain="mydomain"
    ///             EnsureUserIsInGroup="true" />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class AddUser : TaskBase
    {
        private string userName;
        private string[] groupName = new string[0];
        private string userDomain;
        private string[] groupDomain = new string[0];
        private string[] groupMachine = new string[0];
        private bool ensureUserIsInGroup;

        /// <summary>
        /// The machine the the group is on. 
        /// </summary>
        /// <value>If not specified, and GroupDomain not specified then a local group is assumed.</value>
        public string[] GroupMachine
        {
            get { return this.groupMachine; }
            set { this.groupMachine = value; }
        }

        /// <summary>
        /// If "true" and the User is already in the group then no error is thrown.
        /// </summary>
        /// <value>Set to "true" to not throw an error if the user is already in the group</value>
        public bool EnsureUserIsInGroup
        {
            get { return this.ensureUserIsInGroup; }
            set { this.ensureUserIsInGroup = value; }
        }

        /// <summary>The name of the user to add to the group.</summary>
        /// <value>The name of the user.</value>
        [Required]
        public string UserName
        {
            get { return (this.userName == null ? String.Empty : this.userName); }
            set { this.userName = value; }
        }

        /// <summary><para>The groupname to add the user to.</para>
        /// </summary>
        /// <value>The name of the group.</value>
        [Required]
        public string[] GroupName
        {
            get { return this.groupName; }
            set { this.groupName = value; }
        }

        /// <summary>The domain the user belongs to. If not specified it defaults to the local machine.</summary>
        /// <value>The user's domain.</value>
        public string UserDomain
        {
            get { return (this.userDomain == null ? String.Empty : this.userDomain); }
            set { this.userDomain = value; }
        }

        /// <summary><para>The domain the group belongs to.</para>
        /// </summary>
        /// <value>The name of the groups domain.</value>
        public string[] GroupDomain
        {
            get { return this.groupDomain; }
            set { this.groupDomain = value; }
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>        
        protected override void InternalExecute()
        {
            #region Execute code

            if (!AD.User.Exists(this.userName, this.userDomain))
            {
                throw new TaskException("ActiveDirectory.UserDoesNotExist", this.userName);
            }

            AD.User user = null;
            if (!string.IsNullOrEmpty(this.userDomain))
            {
                user = AD.User.Load(this.userName, this.userDomain);
            }
            else
            {
                user = AD.User.Load(this.userName);
            }

            // Now loop through all the groups provided and add the user to each of them

            for (int i = 0; i < this.GroupName.Length; i++)
            {
                string igroupDomain = this.GetGroupDomain(i);
                string igroupName = this.GetGroupName(i);
                string igroupMachine = this.GetGroupMachine(i);

                this.Log.LogMessageFromResources("ActiveDirectory.AddUserToGroup", this.userName, igroupName);

                if (!string.IsNullOrEmpty(igroupDomain))
                {
                    if (!user.IsInDomainGroup(igroupName, igroupDomain))
                    {
                        user.AddToDomainGroup(igroupName, igroupDomain);
                    }
                    else
                    {
                        if (!this.ensureUserIsInGroup)
                        {
                            throw new TaskException("ActiveDirectory.UserAlreadyDomainGroupMember", this.userName, igroupName);
                        }
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(igroupMachine))
                    {
                        if (!user.IsInGroup(igroupName, igroupMachine))
                        {
                            user.AddToGroup(igroupName, igroupMachine);
                        }
                        else
                        {
                            if (!this.ensureUserIsInGroup)
                            {
                                throw new TaskException("ActiveDirectory.UserAlreadyDomainGroupMember", this.userName, igroupName);
                            }
                        }
                    }
                    else
                    {
                        {
                            if (!user.IsInGroup(igroupName))
                            {
                                user.AddToGroup(igroupName);
                            }
                            else
                            {
                                if (!this.ensureUserIsInGroup)
                                {
                                    throw new TaskException("ActiveDirectory.UserAlreadyLocalGroupMember", this.userName, igroupName);
                                }
                            }
                        }
                    }
                }
            }

            #endregion
        }

        private string GetGroupDomain(int index)
        {
            if (index >= this.GroupDomain.Length)
            {
                return null;
            }
            return this.GroupDomain[index];
        }

        private string GetGroupName(int index)
        {
            if (index >= this.GroupName.Length)
            {
                return null;
            }
            return this.GroupName[index];
        }

        private string GetGroupMachine(int index)
        {
            if (index >= this.GroupMachine.Length)
            {
                return Environment.MachineName;
            }
            return this.GroupMachine[index];
        }        
    }
}